package ru.mcfr.oxygen.framework.operations;

import org.apache.log4j.Logger;
import ro.sync.contentcompletion.xml.CIElement;
import ro.sync.contentcompletion.xml.WhatElementsCanGoHereContext;
import ro.sync.ecss.extensions.api.*;
import ro.sync.ecss.extensions.api.access.AuthorTableAccess;
import ro.sync.ecss.extensions.api.node.AttrValue;
import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment;
import ro.sync.ecss.extensions.api.node.AuthorElement;
import ro.sync.ecss.extensions.api.node.AuthorNode;
import ru.mcfr.oxygen.framework.operations.table.Switcher;

import javax.swing.text.BadLocationException;
import java.util.*;

public class GorisontalAlaignOperation implements AuthorOperation {


    private static Logger logger = Logger.getLogger(GorisontalAlaignOperation.class.getName());

    private Map<String, String> parse(String keys, String values, String separator) {

        String[] arKeys = keys.split("\\" + separator);
        String[] arValues = values.split("\\" + separator);
        Map<String, String> map = new HashMap<String, String>();

        int cKeyId = 0;
        for (String cKey : arKeys) {
            String cVal = "";
            if (cKeyId < arValues.length) cVal = arValues[cKeyId++];
            if (!cKey.isEmpty())
                map.put(cKey, cVal);
        }

        return map;
    }

    private Map<String, String> parse(String keys, String values) {
        return parse(keys, values, ",");
    }

    public void doOperation(AuthorAccess authorAccess, ArgumentsMap args) throws IllegalArgumentException, AuthorOperationException {


        AuthorDocumentController controller = authorAccess.getDocumentController();
        AuthorSchemaManager manager = authorAccess.getDocumentController().getAuthorSchemaManager();
        AuthorTableAccess tableContainer = authorAccess.getTableAccess();


        String surrTag = "";
        try {
            surrTag = args.getArgumentValue("каким тегом обернуть").toString();
        } catch (Exception e) {
        }
        String forTag = "";
        try {
            forTag = args.getArgumentValue("применить для тэга").toString();
        } catch (Exception e) {
        }
        String attrName = "";
        try {
            attrName = args.getArgumentValue("атрибут").toString();
        } catch (Exception e) {
        }
        String attrValue = "";
        try {
            attrValue = args.getArgumentValue("значение атрибута").toString();
        } catch (Exception e) {
        }
        boolean groupProcessing = false;
        try {
            groupProcessing = args.getArgumentValue("только для текущего тэга").toString().equals("true");
        } catch (Exception e) {
        }

        String selectedText = "";
        try {
            selectedText = authorAccess.getEditorAccess().getSelectedText();
        } catch (Exception e) {
        }

        int selStart = authorAccess.getEditorAccess().getSelectionStart();
        int selEnd = authorAccess.getEditorAccess().getSelectionEnd();

        AuthorDocumentFragment selFragment;
        List<AuthorNode> selectedNodes = null;
        try {
            selStart = controller.getNodeAtOffset(selStart).getStartOffset();
            selEnd = controller.getNodeAtOffset(selEnd).getEndOffset();
            if (selStart > selEnd) throw new Exception();
            selFragment = controller.createDocumentFragment(selStart, selEnd);
            selectedNodes = selFragment.getContentNodes();
            for (AuthorNode ae : selectedNodes)
                logger.error(ae.getName());
        } catch (BadLocationException e) {
            logger.error(e.getLocalizedMessage());
        } catch (Exception e) {
            logger.error(e.getLocalizedMessage());
        }

        Map<String, String> mapAttr = parse(attrName, attrValue);
        Map<String, String> mapForElems = parse(forTag, "");

        try {

            int currentPosition = authorAccess.getEditorAccess().getCaretOffset();
            if (!selectedText.isEmpty())
                currentPosition = authorAccess.getEditorAccess().getSelectionStart();

            AuthorElement ae = (AuthorElement) controller.getNodeAtOffset(currentPosition);
            boolean weInElement = true;
            try {
                ae.getName();
                ae.getAttribute(attrName).getValue();
            } catch (Exception e) {
                weInElement = false;
            }

            if (surrTag.isEmpty()) {//attr controller
                if (forTag.isEmpty()) {//for element at caret
                    if (ae.getAttribute(attrName).getValue().equals(attrValue)) {
                        for (String key : mapAttr.keySet())
                            controller.removeAttribute(key, ae);
                    } else {
                        for (String key : mapAttr.keySet())
                            controller.setAttribute(key, new AttrValue(mapAttr.get(key)), ae);
                    }
                } else {//for custom element in parents from caret position
                    //for (AuthorNode ae1 : selectedNodes) {
                        for (String curTag : mapForElems.keySet()) {
                            AuthorNode ae1 = (AuthorNode) ae;
                            while (!ae1.getName().equals(curTag))
                                ae1 = ae1.getParent();

                            AuthorElement ae2 = (AuthorElement) ae1;

//                            if (curTag.equals("ячейка") & mapForElems.keySet().contains("таблица")) {
//                                int cols = tableContainer.getTableNumberOfColumns(ae2);
//                                int rows = tableContainer.getTableRowCount(ae2);
//
//                                for (int r = 0; r < rows; r++) {
//                                    for (int c = 0; c < cols; c++) {
//                                        AuthorElement cell = tableContainer.getTableCellAt(r, c, ae2);
//                                        for (String key : mapAttr.keySet()) {
//
//                                            String cAttrValue = "";
//                                            try {
//                                                cAttrValue = cell.getAttribute(key).getValue().toString();
//                                            } catch (Exception e) {
//                                            }
//
//                                            if (cAttrValue.equals(mapAttr.get(key)))
//                                                controller.removeAttribute(key, cell);
//                                            else
//                                                controller.setAttribute(key, new AttrValue(mapAttr.get(key)), cell);
//                                        }
//                                    }
//                                }
//                            } else {
                            for (String key : mapAttr.keySet()) {
                                logger.error(ae2.getLocalName() + ":" + key + "=" + mapAttr.get(key));
                                String cAttrValue = "";
                                try {
                                    cAttrValue = ae2.getAttribute(key).getValue().toString();
                                } catch (Exception e) {
                                }

                                if (cAttrValue.equals(mapAttr.get(key)))
                                    controller.removeAttribute(key, ae2);
                                else
                                    controller.setAttribute(key, new AttrValue(mapAttr.get(key)), ae2);
                            }
                            //}
                        }
                    //}
                }
            } else {
                if (weInElement) {

                    //work with bold, dold_italic, and etc. attr values
                    if (ae.getName().equals("выделение")
                            & !ae.getAttribute(attrName).getValue().equals(attrValue)) {

                        String cAttrValue = "";
                        try {
                            cAttrValue = ae.getAttribute("тип_выделения").getValue().toString();
                        } catch (Exception e) {
                        }

                        Switcher switcher = new Switcher();
                        switcher.initPositionBy_(cAttrValue);
                        String newAttrVal = switcher.toggleByValue_(mapAttr.get("тип_выделения"));

                        ae.removeAttribute("тип_выделения");
                        ae.setAttribute("тип_выделения", new AttrValue(newAttrVal));

                        authorAccess.getEditorAccess().refresh(ae);
                        return;
                    }
                }

                // surrounding
                // WhatAttributesCanGoHereContext neededAttributes =
                // manager.createWhatAttributesCanGoHereContext(ae);
                WhatElementsCanGoHereContext neededElements = manager
                        .createWhatElementsCanGoHereContext(currentPosition);

                int selectionStart = authorAccess.getEditorAccess().getSelectionStart();
                int selectionEnd = authorAccess.getEditorAccess().getSelectionEnd();

                // unsurround
                if (ae.getName().equals(surrTag)) {

                    String textInElement = ae.getTextContent();
                    int mainOffset = ae.getStartOffset();

                    controller.deleteNode(ae);
                    controller.insertText(mainOffset, textInElement);

                    authorAccess.getEditorAccess().select(mainOffset, mainOffset + textInElement.length());
                }

                // surround
                else {
                    final List<CIElement> childrenElements = manager.getChildrenElements(neededElements);
                    for (CIElement e : childrenElements) {

                        if (e.getName().equals(surrTag)) {

//							Content cont = myFragment.getContent();
//							String text = cont.getString(0, cont.getLength());
//							authorAccess.getWorkspaceAccess().showErrorMessage(text);


                            String xmlText = "<" + surrTag + " id=\"\"";

                            //AuthorElement myAE = (AuthorElement) e;
                            //set new attrs
                            if (!mapAttr.isEmpty()) {
                                for (String key : mapAttr.keySet()) {
                                    xmlText = xmlText + " " + key + "=\"" + mapAttr.get(key) + "\"";
                                    //myAE.setAttribute(key, new AttrValue(mapAttr.get(key)));
                                }
                            }

//							final AuthorSchemaManager schemaManager = authorAccess.getDocumentController().getAuthorSchemaManager();
//							AuthorDocumentFragment myFragment = schemaManager.createAuthorDocumentFragment((CIElement) myAE);
//							controller.insertFragment(currentPosition,myFragment);
                            xmlText = xmlText + ">" + selectedText + "</" + surrTag + ">";

                            AuthorDocumentFragment fragment = controller.createNewDocumentFragmentInContext(xmlText, currentPosition);

                            if (!selectedText.isEmpty())
                                controller.delete(selectionStart, selectionEnd - 1);

                            controller.insertFragment(currentPosition, fragment);
                            authorAccess.getEditorAccess().select(selectionStart + 1, selectionEnd + 1);
                        }
                    }
                }
            }

        } catch (BadLocationException e1) {
            authorAccess.getWorkspaceAccess().showErrorMessage("Ошибка вставки/редактирования элемента:" + e1.getMessage());
        }

    }

    public ArgumentDescriptor[] getArguments() {
        ArgumentDescriptor[] res = {
                new ArgumentDescriptor("атрибут", ArgumentDescriptor.TYPE_STRING, ""),
                new ArgumentDescriptor("значение атрибута", ArgumentDescriptor.TYPE_STRING, ""),
                new ArgumentDescriptor("каким тегом обернуть", ArgumentDescriptor.TYPE_STRING, ""),
                new ArgumentDescriptor("применить для тэга", ArgumentDescriptor.TYPE_STRING, ""),
                new ArgumentDescriptor("только для текущего тэга", ArgumentDescriptor.TYPE_STRING, "true/false"),//если ложь то применить операцию для всех тегов в фрагменте
        };
        return res;
    }

    public String getDescription() {
        return "Универсальная функция для работы с атрибутами";
    }

}
